package com.xdja.jwt.imagecollect.mvp.model

import android.app.Application
import com.blankj.utilcode.util.CacheDoubleUtils
import com.blankj.utilcode.util.LogUtils
import com.blankj.utilcode.util.TimeUtils
import com.blankj.utilcode.util.Utils
import com.google.gson.Gson
import com.jess.arms.di.scope.FragmentScope
import com.jess.arms.integration.IRepositoryManager
import com.jess.arms.mvp.BaseModel
import com.xdja.jwt.imagecollect.app.bean.Reload
import com.xdja.jwt.imagecollect.app.bean.User
import com.xdja.jwt.imagecollect.app.db.database.DatabaseManager
import com.xdja.jwt.imagecollect.app.db.entity.UploadFileBean
import com.xdja.jwt.imagecollect.app.ext.getTrunkUploadUrl
import com.xdja.jwt.imagecollect.app.net.FilesApi
import com.xdja.jwt.imagecollect.app.utils.Constant
import com.xdja.jwt.imagecollect.mvp.contract.UploadingContract
import io.reactivex.Flowable
import kotlinx.coroutines.*
import okhttp3.MediaType.Companion.toMediaTypeOrNull
import okhttp3.RequestBody.Companion.toRequestBody
import org.simple.eventbus.EventBus
import java.io.File
import java.net.URLEncoder
import java.text.SimpleDateFormat
import javax.inject.Inject
import kotlin.coroutines.EmptyCoroutineContext

/**
 * @author yuanwanli
 * @date 08/27/2019
 * @des  上传界面的model
 */
@FragmentScope
class UploadingModel
@Inject
constructor(repositoryManager: IRepositoryManager) : BaseModel(repositoryManager), UploadingContract.Model {
    @Inject
    lateinit var mGson: Gson
    @Inject
    lateinit var mApplication: Application

    private var scopeMap: MutableMap<Int, CoroutineScope> = mutableMapOf()

    companion object {
        const val READMAX = 1024 * 100
    }

    override fun uploadBean(bean: UploadFileBean) {
        val coroutineScope = CoroutineScope(EmptyCoroutineContext)
        scopeMap[bean.id] = coroutineScope
        bean.hasStart = true
        bean.hasError = false
        DatabaseManager.getInstance(Utils.getApp()).fileDao().insertOrUpdateUploadBean(bean)
        coroutineScope.launch(Dispatchers.Main) {
            toUploadBean(bean)
        }
    }

    override fun stopUploadBean(bean: UploadFileBean) {
        val scope = scopeMap[bean.id]
        scope?.cancel()
        scopeMap.remove(bean.id)
    }

    private suspend fun toUploadBean(bean: UploadFileBean) {
        try {
            val fileBean = withContext(Dispatchers.IO) {
                return@withContext DatabaseManager.getInstance(Utils.getApp()).fileDao()
                    .getUploadBean(bean.id)
            }
            if (fileBean.uploadSize < bean.totalSize) {
                var result: ByteArray?
                var responseBody = withContext(Dispatchers.IO) {
                    val requestBody = File(bean.filePath).inputStream().use {
                        //剩余未上传byte
                        val residue = fileBean.totalSize - fileBean.uploadSize
                        result = if (residue >= READMAX) {
                            ByteArray(READMAX)
                        } else {
                            ByteArray(residue.toInt())
                        }
                        it.skip(fileBean.uploadSize)
                        it.read(result)
                        result?.toRequestBody("application/octet-stream".toMediaTypeOrNull())
                    }
                    result = null
                    val encode = URLEncoder.encode(bean.filename, "UTF-8")
                    if (bean.fastdfs_id.isEmpty()) {
                        return@withContext mRepositoryManager.obtainRetrofitService(FilesApi::class.java)
                            .uploadFile(
                                getTrunkUploadUrl(),
                                body = requestBody!!,
                                fileName = encode,
                                fileSize = bean.totalSize
                            )
                    } else {
                        return@withContext mRepositoryManager.obtainRetrofitService(FilesApi::class.java)
                            .uploadFile(
                                getTrunkUploadUrl(),
                                body = requestBody!!,
                                fileid = bean.fastdfs_id,
                                fileName = encode,
                                fileSize = bean.totalSize
                            )
                    }
                }
                if (fileBean.fastdfs_id.isEmpty()) {
                    fileBean.fastdfs_id = responseBody.fileid
                }
                fileBean.uploadSize = responseBody.size
                if (responseBody.size >= fileBean.totalSize) {
                    fileBean.state = 1
                    fileBean.updateTime =
                        TimeUtils.getNowString(SimpleDateFormat("yyyy-MM-dd HH:mm"))
                    EventBus.getDefault().post(Reload())//发射事件,让已上传界面更新
                    DatabaseManager.getInstance(Utils.getApp()).fileDao()
                        .insertOrUpdateUploadBean(fileBean)
                } else {
                    DatabaseManager.getInstance(Utils.getApp()).fileDao()
                        .insertOrUpdateUploadBean(fileBean)
                    toUploadBean(fileBean)
                }
            }
        } catch (e: Exception) {
            LogUtils.e(e)
            if (e !is CancellationException) {
                bean.hasError = true
            }
            bean.hasStart = false
            DatabaseManager.getInstance(Utils.getApp()).fileDao().insertOrUpdateUploadBean(bean)
        }
    }

    override fun insertBeans(
        arrayList: ArrayList<String>,
        foldId: String,
        foldName: String
    ) {
        val user = CacheDoubleUtils.getInstance().getParcelable(Constant.LOGIN_CACHE, User.CREATOR)
        arrayList.forEach {
            var file = File(it)
            var bean = UploadFileBean()
            bean.filePath = file.absolutePath
            bean.filename = file.name
            bean.totalSize = file.length()
            bean.foldId = foldId
            bean.folderName = foldName
            bean.policeId = user.id
            DatabaseManager.getInstance(Utils.getApp()).fileDao().insertOrUpdateUploadBean(bean)
        }
    }

    override fun getAllLoadingBean(): Flowable<List<UploadFileBean>> {
        val user = CacheDoubleUtils.getInstance().getParcelable(Constant.LOGIN_CACHE, User.CREATOR)
        return DatabaseManager.getInstance(Utils.getApp()).fileDao().getAllUploadBean(user.id, 0)
    }

    override fun onDestroy() {
        super.onDestroy()
        scopeMap.forEach {
            it.value.cancel()
        }
        scopeMap.clear()
    }
}
